using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Comteck.Winforms.Infrastructure.ToExcel.Attributes;
using NPOI.SS.UserModel;

namespace Comteck.Winforms.Infrastructure.ToExcel.Converter {
  /// <summary>
  /// 这是一个基本转化器的包装类
  /// <see cref="https://gitee.com/godenSpirit/mto-excel/blob/master/MToExcel/Converter/WrapperConverter.cs"/>
  /// </summary>
  public class WrapperConverter {
    // 类型池，用来保存打了Attribute的标签的自定义类型
    public static Dictionary<Type, ReferenceTypeAttribute> ReferenceTypePool = new Dictionary<Type, ReferenceTypeAttribute>();
    public static Dictionary<Type, IgnoreTypeAttribute> IgnoreTypePool = new Dictionary<Type, IgnoreTypeAttribute>();
    public static Dictionary<Type, HeaderNameAttribute> CustomNamePool = new Dictionary<Type, HeaderNameAttribute>();
    /// <summary>
    /// target对象，用来具体的打表
    /// </summary>
    public BasicConvert Basic = null;

    public WrapperConverter() {
      this.Basic = new BasicConvert();
    }

    public IWorkbook ConvertToExcel<T>(List<T> list) {
      // 在调target执行真正的方法之前，在此可以设置增强方法
      this.CheckAttribute(typeof(T));

      return this.Basic.ConvertToExcel(list);
    }

    /// <summary>
    /// (增强方法)检查泛型类型的属性中是否带有自定义的Reference的标签
    /// </summary>
    /// <param name="type"></param>
    private void CheckAttribute(Type type) {
      var properties = type.GetProperties();

      // 遍历获取属性中的Attribute对象
      foreach (var property in properties) {
        var referType = (ReferenceTypeAttribute) property.GetCustomAttribute(typeof(ReferenceTypeAttribute));
        var ignoreType = (IgnoreTypeAttribute) property.GetCustomAttribute(typeof(IgnoreTypeAttribute));
        var headerName = (HeaderNameAttribute) property.GetCustomAttribute(typeof(HeaderNameAttribute));

        // 检查属性是否存在标签，存在就保存到类型中
        if (referType != null) {
          // 将打了标记的类型和标记本身放到类型池中
          ReferenceTypePool.Add(property.PropertyType, referType);
        }

        if (ignoreType != null) {
          IgnoreTypePool.Add(property.PropertyType, ignoreType);
        }

        if (headerName != null) {
          CustomNamePool.Add(property.PropertyType, headerName);
        }
      }
    }
  }
}
